#define ETHERTYPE_IPV4 0x0800
#define ETHERTYPE_VLAN 0x8100
#define IPv4_TCP 0x06
#define IPv4_UDP 0x11

/*++++++++++ start ++++++++++*/
parser start {
    return parse_ethernet;
}

/*++++++++++ parse_ethernet ++++++++++*/
parser parse_ethernet {
  extract(ethernet);
  return select(latest.etherType) {
  ETHERTYPE_IPV4 : parse_ipv4;
  ETHERTYPE_VLAN: parse_vlan_tag;
  default: ingress;
  }
}

field_list ipv4_checksum_list {
    ipv4.version;
    ipv4.ihl;
    ipv4.diffserv;
    ipv4.totalLen;
    ipv4.identification;
    ipv4.flags;
    ipv4.fragOffset;
    ipv4.ttl;
    ipv4.proto;
    ipv4.srcip;
    ipv4.dstip;
}

field_list_calculation ipv4_checksum {
    input {
        ipv4_checksum_list;
    }
    algorithm : csum16;
    output_width : 16;
}

calculated_field ipv4.hdrChecksum  {
    verify ipv4_checksum;
    update ipv4_checksum;
}

/*++++++++++ parse_vlan_tag ++++++++++*/
parser parse_vlan_tag {
  extract(vlan_tag);
  return select(latest.etherType) {
  ETHERTYPE_IPV4 : parse_ipv4;
  default : ingress;
  }
}

/*++++++++++ parse_ipv4 ++++++++++*/
parser parse_ipv4 {
    extract(ipv4);
    return select(latest.proto){
    IPv4_TCP: parse_tcp;
    IPv4_UDP: parse_udp;
    default: ingress;
    }
}

/*++++++++++ parse_tcp ++++++++++*/
parser parse_tcp {
    extract(tcp);
    return ingress;
}

/*++++++++++ parse_udp ++++++++++*/
parser parse_udp {
  extract(udp);
  return ingress;
}
